package handles

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/global/constant"
	mqConstant "github.com/Sir-yuChen/funAnalyse/global/mq"
	"github.com/Sir-yuChen/funAnalyse/model"
	"github.com/Sir-yuChen/funAnalyse/model/common/ApiReturn"
	"github.com/Sir-yuChen/funAnalyse/service/commonService"
	"github.com/Sir-yuChen/funAnalyse/utils"
	"github.com/Sir-yuChen/funAnalyse/utils/kafka"
	"github.com/robfig/cron/v3"
	"go.uber.org/zap"
	"strings"
)

type BulletinTimerHandle struct {
	taskId     int
	task       model.StockTImer
	uniqueCode string
}
type parameterModel struct {
	BulletinName string `json:"bulletinName,omitempty"`
}

// NewBulletinTimerHandle 无参构造 用来添加 Assignment
func NewBulletinTimerHandle() *BulletinTimerHandle {
	return &BulletinTimerHandle{}
}

// Assignment 所有定时任务都要按照规则实现该方法添加具体实现类 以及所需要的额外参数 该方法仅用于添加参数和添加任务
func (b BulletinTimerHandle) Assignment(timer model.StockTImer, params map[string]interface{}, option ...cron.Option) error {
	//当前对象不能用指针类型，避免多次添加任务覆盖数据
	b.task = timer
	b.uniqueCode = timer.UniqueCode
	id, err := global.GVA_Timer.AddTaskByJob(timer.UniqueCode, timer.TimerSpec, &b, option...)
	if err != nil || id == -1 {
		global.GVA_LOG.Error("JOB 定时任务添加失败", zap.Any("StockTImer", timer), zap.Error(err))
	} else {
		global.GVA_LOG.Info("JOB 定时任务添加成功", zap.Any("timer_id", id), zap.Any("StockTImer", timer))
	}
	b.taskId = int(id)
	return err
}

// Run 定时任务具体业务实现 run接口
func (b *BulletinTimerHandle) Run() {
	global.GVA_LOG.Info("推送公告任务执行 JOB》》》》", zap.Any("timer", b.task))
	taskDB, err := TimerHandlePreOperation("BulletinTimerHandle", b.taskId, b.task)
	if err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 前置校验异常", zap.Any("UniqueCode", taskDB.UniqueCode), zap.Error(err))
		return
	}
	/** 具体业务
	1. 过滤数据源  解析获取定时任务附带的参数，并找到对应的公告详情
	2. 根据公告详情-->面向的公告群体----》根据具体的用户群体获取用户群，MQ
	3. 注意校验公告状态和用户群状态
	*/
	parameter := taskDB.Parameter
	if parameter == "" {
		global.GVA_LOG.Error("BulletinTimerHandle 定时任务为附带参数为空", zap.Any("UniqueCode", taskDB.UniqueCode))
		return
	}
	var parameterMo parameterModel
	var bulletin model.StockBulletinModel
	var userGroups []model.StockUserGroupModel
	if err = json.Unmarshal([]byte(parameter), &parameterMo); err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle stringJson-->struct数据转换异常", zap.Any("parameter", parameter), zap.Error(err))
		return
	}
	if err = global.GVA_DB.Model(&bulletin).Where(" bulletin_name = ? ", parameterMo.BulletinName).First(&bulletin).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 查询公告详情异常", zap.Any("UniqueCode", taskDB.UniqueCode), zap.Any("bulletinName", parameterMo.BulletinName))
		return
	}
	split := strings.Split(bulletin.BulletinGroupId, ",")
	if err = global.GVA_DB.Model(model.StockUserGroupModel{}).Where(" id in (?) ", split).Find(&userGroups).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 查询用户群异常", zap.Any("UniqueCode", taskDB.UniqueCode), zap.Any("bulletin", bulletin))
		return
	}
	//处理获取用户群
	userIds, err := b.getUserGroup(userGroups)
	if err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 获取用户群异常", zap.Any("UniqueCode", taskDB.UniqueCode), zap.Error(err))
		return
	}
	if err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle MQ连接异常", zap.Any("UniqueCode", taskDB.UniqueCode), zap.Error(err))
		return
	}
	//RabbitMq 发送消息
	/*
		queueExchange := rabbitMq.QueueExchange{
			QuName: mqConstant.MQ_QUEUE_BULLETIN,
			RtKey:  mqConstant.MQ_ROUTING_KEY_BULLETIN_1,
			ExName: mqConstant.MQ_EXCHANG_BULLETIN,
			ExType: mqConstant.MQ_EX_TYPE_direct,
		}
		for _, userId := range userIds {
			if userId == "" {
				continue
			}
			mqMsg := map[string]interface{}{
				"userId":                userId,
				"bulletinMainTitle":     bulletin.BulletinMainTitle,
				"bulletinSubtitleTitle": bulletin.BulletinSubtitleTitle,
				"bulletinType":          bulletin.BulletinType,
				"bulletinContent":       bulletin.BulletinContent,
				"bulletinId":            bulletin.Id,
			}
			jsonStr, err := json.Marshal(mqMsg)
			if err != nil {
				global.GVA_LOG.Error("InsertStockBulletin异常 数据转换异常", zap.Any("Msg", mqMsg), zap.Error(err))
				continue
			}
			rabbitMq.Send(queueExchange, string(jsonStr))
			//发送成功 将源数据落缓存以便下次取用 todo
		}
	*/
	//kafka 发送消息
	producer, err := kafka.GetKafkaProducer(global.GVA_CONFIG.KafkaConfig.Link)
	if err != nil {
		global.GVA_LOG.Error("创建kafka连接异常", zap.Error(err))
		return
	}
	defer func() {
		if err = producer.Close(); err != nil {
			global.GVA_LOG.Error(" close kafka producer err!", zap.Error(err))
		}
	}()
	sep := 1
	for _, userId := range userIds {
		if userId == "" {
			continue
		}
		mqMsg := map[string]interface{}{
			"userId":                userId,
			"bulletinMainTitle":     bulletin.BulletinMainTitle,
			"bulletinSubtitleTitle": bulletin.BulletinSubtitleTitle,
			"bulletinType":          bulletin.BulletinType,
			"bulletinContent":       bulletin.BulletinContent,
			"bulletinId":            bulletin.Id,
		}
		jsonStr, err := json.Marshal(mqMsg)
		if err != nil {
			global.GVA_LOG.Error("InsertStockBulletin异常 数据转换异常", zap.Any("Msg", mqMsg), zap.Error(err))
			continue
		}
		err = kafka.SendMsgToKafka(producer, mqConstant.MQ_KAFKA_BULLETI, userId, string(jsonStr), sep)
		if err != nil {
			continue
		} else {
			sep++
		}
		//发送成功 将源数据落缓存以便下次取用  todo
	}
	defer func() {
		err = TimerHandlePostOperation("BulletinTimerHandle", b.taskId, taskDB, err)
		if err != nil {
			global.GVA_LOG.Error("BulletinTimerHandle 后置校验异常", zap.Any("UniqueCode", taskDB.UniqueCode))
			return
		}
	}()
}

func (b *BulletinTimerHandle) getUserGroup(userGroups []model.StockUserGroupModel) (ids []string, err error) {
	userIds := make([]string, 100)
	for _, group := range userGroups {
		//判断用户群状态
		if group.Status != constant.STATUS_Y {
			global.GVA_LOG.Warn("BulletinTimerHandle 用户群状态不可用", zap.Any("userGroup", group))
			continue
		}
		//数据获取应先从缓存获取在查数据库 除文件以外
		ids := make([]string, 10)
		switch int(group.GroupType) {
		case constant.USER_GROUP_TYPE_FILE: //文件
			if group.FileId == "" {
				global.GVA_LOG.Error("BulletinTimerHandle 用户来源,文件,文件ID不能为空", zap.Any("userGroup", group))
				return nil, errors.New(ApiReturn.ErrParam.Msg)
			}
			ids, err = b.getCustomerIdByFile(group)
			break
		case constant.USER_GROUP_TYPE_ROLE: //角色
			if group.RoleIds == "" {
				global.GVA_LOG.Error("BulletinTimerHandle 用户来源,角色,角色ID不能为空", zap.Any("userGroup", group))
				return nil, errors.New(ApiReturn.ErrParam.Msg)
			}
			ids, err = b.getCustomerIdByRoles(group)
			break
		case constant.USER_GROUP_TYPE_POSITION: //特定职位身份
			if group.PositionIds == "" {
				global.GVA_LOG.Error("BulletinTimerHandle 用户来源,职位身份,职位身份ID不能为空", zap.Any("userGroup", group))
				return nil, errors.New(ApiReturn.ErrParam.Msg)
			}
			ids, err = b.getCustomerIdByPositions(group)
			break
		case constant.USER_GROUP_TYPE_USERNAME: //特定用户注意用户建议不要太多
			if group.UserNames == "" {
				global.GVA_LOG.Error("BulletinTimerHandle 用户来源,指定用户名,用户名不能为空", zap.Any("userGroup", group))
				return nil, errors.New(ApiReturn.ErrParam.Msg)
			}
			ids, err = b.getCustomerIdByUserNames(group)
			break
		case constant.USER_GROUP_TYPE_DEPT: // 指定部门
			if group.DeptIds == "" {
				global.GVA_LOG.Error("BulletinTimerHandle 用户来源,部门,部门ID不能为空", zap.Any("userGroup", group))
				return nil, errors.New(ApiReturn.ErrParam.Msg)
			}
			ids, err = b.getCustomerIdByDepts(group)
			break
		default:
			global.GVA_LOG.Warn("BulletinTimerHandle 未知的用户来源", zap.Any("userGroup", group))
			continue
		}
		if len(ids) > 0 && len(userIds) > 0 {
			userIds = utils.MergeArr(userIds, ids)
		} else {
			userIds = ids
		}
		if err != nil {
			global.GVA_LOG.Warn("BulletinTimerHandle 执行异常", zap.Any("ERROR", err))
			continue
		}
	}
	return userIds, nil
}

//根据文件获取用户群
func (b BulletinTimerHandle) getCustomerIdByFile(group model.StockUserGroupModel) (userIds []string, e error) {
	//获取对应的文件详情
	var files []model.StockFilesModel
	split := strings.Split(group.FileId, ",")
	if err := global.GVA_DB.Model(model.StockFilesModel{}).Where("id in(?) AND status = ?", split, constant.STATUS_Y).Find(&files).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,文件,获取文件详情异常", zap.Any("userGroup", group), zap.Error(err))
		return nil, err
	}
	//读取文件获取数据
	for _, f := range files {
		excel, err := commonService.ReadDataFromExcel(f)
		if err != nil {
			global.GVA_LOG.Error("BulletinTimerHandle 用户来源,文件,读取文件获取数据异常", zap.Any("file", f), zap.Error(err))
			continue
		}
		for _, item := range excel.ExcelData {
			for _, m := range item {
				v, ok := m["customer_id"]
				if ok && v != "" {
					userIds = append(userIds, fmt.Sprint(v))
				}
			}
		}
	}
	return userIds, nil
}

//根据角色获取用户群
func (b BulletinTimerHandle) getCustomerIdByRoles(group model.StockUserGroupModel) ([]string, error) {
	userIds := make([]string, 100)
	split := strings.Split(group.RoleIds, ",")
	if err := global.GVA_DB.Model(model.StockCasbinRoleRelationUserModel{}).Select("user_id").Where("role_id in(?) AND status = ?", split, constant.STATUS_Y).Find(&userIds).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,角色,查用户角色关系异常", zap.Any("userGroup", group), zap.Error(err))
		return nil, err
	}
	if len(userIds) <= 0 {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,角色,没有用户拥有当前角色", zap.Any("userGroup", group))
	}
	return userIds, nil
}

//根据职位身份获取用户群
func (b BulletinTimerHandle) getCustomerIdByPositions(group model.StockUserGroupModel) ([]string, error) {
	userIds := make([]string, 100)
	//TODO 根据身份ID查身份标识，批量查符合身份的用户
	return userIds, nil
}

//根据指定用户名获取用户群
func (b BulletinTimerHandle) getCustomerIdByUserNames(group model.StockUserGroupModel) ([]string, error) {
	split := strings.Split(group.UserNames, ",")
	userIds := make([]string, len(split))
	if err := global.GVA_DB.Model(model.StockUser{}).Select("customer_id").Where("customer_name in(?) AND status = ?", split, constant.STATUS_Y).Find(&userIds).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,指定用户名,用户名查用户ID异常", zap.Any("userGroup", group), zap.Error(err))
		return nil, err
	}
	return userIds, nil
}

//根据部门获取用户群
func (b BulletinTimerHandle) getCustomerIdByDepts(group model.StockUserGroupModel) ([]string, error) {
	userNames := make([]string, 100)
	split := strings.Split(group.DeptIds, ",")
	for _, id := range split {
		names, err := getDeptAllUserName(id, nil)
		if err != nil {
			continue
		}
		userNames = utils.MergeArr(userNames, names)
	}
	userIds := make([]string, len(userNames))
	if err := global.GVA_DB.Model(model.StockUser{}).Select("customer_id").Where("customer_name in(?) AND status = ?", userNames, constant.STATUS_Y).Find(&userIds).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,部门,用户名查用户ID异常", zap.Any("userGroup", group), zap.Error(err))
		return nil, err
	}
	return userIds, nil
}
func getDeptAllUserName(id string, userNames []string) ([]string, error) {
	var dept model.StockDeptModel
	names := make([]string, 100)
	childIds := make([]string, 10)
	if err := global.GVA_DB.Model(model.StockDeptModel{}).Where("id = ?  AND status = ?", id, constant.STATUS_Y).First(&dept).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,指定部门,查部门信息异常", zap.Error(err))
		return nil, err
	}
	if err := global.GVA_DB.Model(model.StockDeptModel{}).Select("dept_staff").Where("parent_id = ?  AND status = ?"+
		" And type = ?", id, constant.STATUS_Y, constant.DEPT_STAFF).Find(&names).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,指定部门,查部门中的员工异常", zap.Error(err))
		return nil, err
	}
	//查询是否有子部门
	if err := global.GVA_DB.Model(model.StockDeptModel{}).Select("id").Where("parent_id=? And status=?", id, constant.STATUS_Y).Find(&childIds).Error; err != nil {
		global.GVA_LOG.Error("BulletinTimerHandle 用户来源,指定部门,查部门是否存在子部门异常", zap.Error(err))
		return nil, err
	}
	names = utils.MergeArr(names, userNames)
	if len(childIds) > 0 {
		for _, childId := range childIds {
			name, err := getDeptAllUserName(childId, names)
			names = utils.MergeArr(name, names)
			if err != nil {
				return nil, err
			}
		}
	}
	return names, nil
}
